/* classes: RVParse, RVRename, RVDirectives, HashTblIter  */ 

#ifndef RV_PARSE_H
#define RV_PARSE_H

#include <fstream>
#include <iostream>
#include <map>
#include <memory>

#include <rv_ctool.h>
#include "rv_side.h"

class FunctionDef;


/* RVParse - 
	 A base virtual class which defines the hooks
	 we use to introduce our parse changes into the 
	 grammer code.
*/

class RVParse : public RVCtool /* inherit ctool interface funcs */
{
  protected:
	Project *parsetree;

	bool in_body;      /* we are already inside the function body. */
	bool in_tag_def;   /* we are inside an struct/union/enum definition */

	virtual void end_body() { in_body = false; }

  public:
	bool next_is_comp;     /* next symbol is struct/union component */
	bool ignore_undefined; /* don't warn about undefined symbols. */

	RVParse();
	virtual ~RVParse();

	bool parse_path(const std::string& fname, const std::string& description);

	virtual bool do_parse(std::istream *_instream, const std::string& fname);

	/* By default the next functions do nothing: */
	virtual void flush_buffer(Statement* st = NULL) { end_body(); }

	virtual void collect(char* token_text, int token_len) {}
	virtual void insert_prefix(char* sym, int len, const char *prefix) {}
	virtual void insert_side_prefix(SymEntry* se, char *sym, int len, int clevel) {}

	virtual void process_label(const std::string& name) {}

	virtual void grab_scope( std::string& func_name ) {}

	virtual void start_body() { in_body = true; }
	virtual void start_tag_def() { in_tag_def = true; }
	virtual void end_tag_def() { in_tag_def = false; }

	bool is_in_body() { return in_body; }

	static bool ignore_func(const std::string& fname);

	/* functions whose bodies are generated by RVTemp: */
	static bool supplied_by_rvt(const std::string& fname);

	SymEntry* lookup_global_var(const std::string& name);
	SymEntry* lookup_function(const std::string& name);

	SymEntry* lookup_symbol_in_current_contxt(std::string& name);
	SymEntry* lookup_symbol_in_global_contxt(std::string& name);

	Project *take_parsetree();

	// add/delete FunctionDefs of external functions:
	static FunctionDef* add_empty_body(SymEntry* se);
	static bool add_func_empty_bodies(Project* parsetree);
	static bool delete_func_empty_bodies(Project* parsetree);
	static bool delete_parsetree(Project* parsetree);

	virtual bool add_func_empty_bodies(); // on current parsetree
};



/* RVGlobLists
	 a parser which also collects all global decls (of types, vars and
	 funcs) in list by the order of declaration. 
	 A list is constructed for each side.
*/

class RVGlobLists : public RVParse {
	struct RVOutlineArgTypes {
		BinaryExpr m_result;
		std::string m_lTypeName, m_rTypeName;

		RVOutlineArgTypes(BinaryOp  op,
                          Expression *lexpr,
                          Expression *rexpr,
                          const std::string& lTypeName,
                          const std::string& rTypeName);
	};
	typedef std::map<std::pair<int, std::string>, RVOutlineArgTypes*> RVOutlineMapping;

  protected:
	int  current_side;    
	bool uses_mult[2];
	bool uses_div[2];
	bool uses_mod[2];
	RVOutlineMapping m_outlineFuncNames;

  public:
	Project *side_parsetree[2];

	RVGlobLists();
	virtual ~RVGlobLists();

	void clear(); /* clear StemntVecs and delete parsetrees */

	void set_side(const RVSide& side) { current_side = side.index(); }

	virtual bool do_parse(std::istream *_instream, const std::string& fname);

	virtual bool add_func_empty_bodies(); // on current parsetree

	Project*  get_parsetree(const RVSide& side) const;
	ScopeTbl* get_file_scope(const RVSide& side, SymEntryType entry_type = VarDeclEntry,
							 bool exit_on_error = true);
	ScopeTbl* get_file_tags(const RVSide& side);

	bool is_needed(const std::string& func_name, const RVSide& side);
	AssignExpr* outline_assignment(AssignOp _op, Expression *lExpr, Expression *rExpr, const Location& l); // ofer. change tag: OUTLINE_FUNCS
	Expression* outline(BinaryOp _op, Expression *lExprOrig, Expression *rExprOrig, const Location& l); //change tag: OUTLINE_FUNCS
	void add_outline_bodies(std::string side0_fname, std::string side1_fname, bool refined);

  private:
	void outlineDefaultFuncName(std::string& func_name, BinaryOp _op);
	void outlineBaseTypesFuncName(std::string& func_name,
			                      BinaryOp _op,
			                      std::auto_ptr<Expression> &lExpr,
			                      std::auto_ptr<Expression> &rExpr,
                                  Type *lbt,
                                  Type *rbt);
	void defineTypeSpecificOutlineFunc(const std::string& funcName,
			                           RVOutlineArgTypes& argTypes,
			                           std::ofstream& fout,
			                           int sideNum,
			                           bool refined);
	SymEntry *makeOutlineFuncSymEntry(const std::string& genOpFuncName,
			                          const std::string& func_name);
};

extern RVGlobLists rv_parser;



class RVDirectives;
class RVFuncPair;

/* RVRename -
	 used to rename the func and var identifiers 
	 on each side during parsing.
	 It uses a buffer in which it collects all the 
	 text of a single function or declaration.
	 When it reaches an identifier it should rename,
	 it renames it in the buffer moving forward the 
	 chars which where collected after the identifier.
	 When the function or the declaration is fully
	 parsed the buffer is flushed to the output. 
*/

class RVRename : public RVParse
{
  protected:
	int  buf_size, next;
	char *buf;

	std::ostream *outstream;
	RVDirectives *directs;

	RVSide current_side;
	bool static_renamer; /* doesn't parse. */
	bool exclude_vars;   /* don't rename vars - mainly for Decls */
	bool semchk_use_uf_prefix;
	char *func_name;
	int  func_name_len;

	RVFuncPair* semchk_pair;
	bool semchk_recursive; 

	virtual void end_body();

	void init();

  public:
	RVRename(int _buf_size);

	/* for static renaming - not parsing renamer: */
	RVRename(Project *_parsetree, const RVSide& _side, bool _exclude_vars = false);

	virtual ~RVRename();

	virtual void flush_buffer(Statement* st = NULL);
	char*   find_nested_proto_end();
	void    gen_semchk_proto(char* end_proto);

	char* find_func_name(int& len);

	void discard_buffer();

	virtual void collect(char* token_text, int token_len);        /* collect in the buffer */
	virtual void insert_prefix(char* sym, int len, const char *prefix);
	/* add current side prefix to an identifier: */
	virtual void insert_side_prefix(SymEntry* se, char *sym_name, int len, int clevel);  

	/* if it is a check point label - insert the code for it: */
	virtual void process_label(const std::string& name);

	void write_check_code( std::string* pchan, std::string* pcond, std::string* pval);
	void insert_check_point(SymEntry *se);

	SymEntry* get_loop_pvar_symbol(std::string& ref_name);

	int  copy_with_prefix(const char* symbol, int symbol_len, char* buf, int buf_len );
	std::string convert_ids(const std::string& code);

	void set_side(const RVSide& side);
	void set_output(std::ostream *_outstream);
	void set_directs(RVDirectives* _dirs);
	void set_semchk_pair(RVFuncPair* pair, bool recursive);
};



/* RVDirectives - 
	 parses the assertions file where channels and check-points are
	 defined. This class uses the same C syntax and renaming abilities
	 but also collects check points and channel names.
	 Channels are defined as a var of type "CHANNEL".
	 Check points are defines as local vars of functions
	 SIDE0_CHECK_POINTS() and SIDE1_CHECK_POINTS() for the respective
	 sides. "DCP" is the struct typedef for Default Check Points which
	 use the default channel, their initializers contain the check
	 condition and the collected/checked value as strings.
	 "CP" is the struct typedef for Check Points which use other
	 channels when the name of the channel comes as the first string
	 in the initializer.
*/

class RVDirectives : public RVParse
{
  protected:
	bool active; // by default directives is off. Can be turned on by command-line flag

	ScopeTbl* cpTbl[2];  /* check points table for each side. */
	ScopeTbl* ffTbl[2];  /* special function flags */
	ScopeTbl* shTbl[2];  /* shape labels tables */ 

	ScopeTbl* chanTbl;   /* table of channels */

	unsigned get_func_flags(SymEntry* se);

	ScopeTbl** which_scope(std::string& func_name, int& out_side, 
			   std::string& out_scope_name, bool& out_label_scope);

	

  public:
	RVDirectives();
	virtual ~RVDirectives();

	/* does RVParse::do_parse() but also grabs the main scope (channel
		  scope) at the end:  */
	void activate() {active = true;}
	bool is_active() {return active;}

	virtual bool do_parse(std::istream *_instream, const std::string& fname);
	virtual bool after_parse() { return true; }

	virtual void grab_scope( std::string& func_name );

	static bool is_channel(SymEntry* se);
	bool is_channel( const std::string& name );
	SymEntry* lookup_channel( const std::string& name );
	unsigned  get_func_flags( int side, const std::string& name );

	SymEntry* lookup_label( const RVSide& side, const std::string& name );

	HashTblIter get_channels_iter();

	Block* get_shape_block(int side, const Type* shape_type);

	static ExprVector* get_check_point_vals(SymEntry* se, std::string& type_name);
};

extern RVDirectives rv_directs;

/* this will point to the current parser tool: RVParse, RVRename or RVDirectives */
extern RVParse *prvhooks;

#endif /* RV_PARSE_H */

